spring @import注解原理解析

@import

  我们可以用这个注解导入bean到容器里面。

3个方式

直接@import

  导入的baen

@Data
public class User {
    private Integer id;
    private String name;
}

  导入方法:

@Configuration
@Import(value = { User.class })
public class Config {

}

通过ImportBeanDefinitionRegistrar

  还是上面的bean。但是 不是直接导入。

public class UserServiceBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {

public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
    BeanDefinitionBuilder user = BeanDefinitionBuilder.rootBeanDefinition(User.class);
    // 通过registry就可以注入到容器里啦
    registry.registerBeanDefinition("user", user.getBeanDefinition());
}
}

  注解方法:

@Configuration
@Import(value = { UserServiceBeanDefinitionRegistrar.class })
public class Config {

}

通过ImportSelector

public class UserServiceImportSelect implements ImportSelector {
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
    return new String[] { User.class.getName() };
}
}

  注解方法:

@Configuration
@Import(value = { UserServiceImportSelect.class })
public class Config {

}

小结

  上述3个方法都可以将bean导入到springbean容器里面。

源码分析

  老规矩,我们从springboot的启动开始分析,虽然这直接属于spring那一块。我们从run开始点点点,进入下面方法。

public ConfigurableApplicationContext run(String... args) {
        ......
        refreshContext(context);
        ......
}

  直接关注这个方法,这个方法会调用核心,他是spring容器启动的核心方法。
  然后不断点点,进入到这个核心方法。

    @Override
public void refresh() throws BeansException, IllegalStateException {
    synchronized (this.startupShutdownMonitor) {
        .....

        invokeBeanFactoryPostProcessors(beanFactory);

        .....


}

  这个方法提取出invokeBeanFactoryPostProcessors方法,点进去。

public static void invokeBeanFactoryPostProcessors(
        ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {

......

List<BeanFactoryPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();

......

invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory);

......
}

 

  进入这个方法后主要有2个方法需要注意。这个接口BeanFactoryPostProcessor的实现类是这个ConfigurationClassPostProcessor。进入invokeBeanFactoryPostProcessors方法。

private static void invokeBeanFactoryPostProcessors(
        Collection<? extends BeanFactoryPostProcessor> postProcessors, ConfigurableListableBeanFactory beanFactory) {

    for (BeanFactoryPostProcessor postProcessor : postProcessors) {
        postProcessor.postProcessBeanFactory(beanFactory);
    }
}

  调用了postProcessBeanFactory方法。然后点点点,进入processConfigBeanDefinitions方法,这个就是处理@import的方法了。

    public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
......
parser.parse(candidates);
......

}

  进入这个方法,不断进入doProcessConfigurationClass这个方法里面。

@Nullable
protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass)
        throws IOException {

    ......
    Set<BeanDefinitionHolder> scannedBeanDefinitions =
                    this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
            // Check the set of scanned definitions for any further config classes and parse recursively if needed
            for (BeanDefinitionHolder holder : scannedBeanDefinitions) {
                BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();
                if (bdCand == null) {
                    bdCand = holder.getBeanDefinition();
                }
                if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {
                    parse(bdCand.getBeanClassName(), holder.getBeanName());
                }
            }
        }
    }

    // Process any @Import annotations
    processImports(configClass, sourceClass, getImports(sourceClass), true); 

    ......
    }

  进去后,第一个方法获取到本项目下所有的bean,然后过滤找到是@Import的bean,再然后在processImports方法里面将其里面的bean注入spring容器进去。